/* Examples/reed_sol_03.cpp
 * James S. Plank

Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure Coding Techniques
Copright (C) 2007 James S. Plank

James S. Plank
Department of Electrical Engineering and Computer Science
University of Tennessee
Knoxville, TN 37996
plank@cs.utk.edu
*/
  
/*
 * $Revision: 1.2 $
 * $Date: 2008/08/19 17:41:40 $
 */


/*
	revised by S. Simmerman
	2/25/08  
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jerasure-2.h"
#include "reed_sol-2.h"
using namespace std;

void usage(char *s)
{
  fprintf(stderr, "usage: reed_sol_03 k w - Does a simple RAID-6 coding example in GF(2^w).\n");
  fprintf(stderr, "       \n");
  fprintf(stderr, "       w must be 8, 16 or 32.  k+2 must be <= 2^w.  It sets up a classic\n");
  fprintf(stderr, "       RAID-6 coding matrix based on Anvin's optimization and encodes\n");
  fprintf(stderr, "       %ld-byte devices with it.  Then it decodes.\n", sizeof(long));
  fprintf(stderr, "       \n");
  fprintf(stderr, "This demonstrates: reed_sol_r6_encode()\n");
  fprintf(stderr, "                   reed_sol_r6_coding_matrix()\n");
  fprintf(stderr, "                   JER_Matrix_Decode()\n");
  fprintf(stderr, "                   JER_Matrix::Print()\n");
  if (s != NULL) fprintf(stderr, "%s\n", s);
  exit(1);
}

static void print_data_and_coding(JER_Slices *slices)
{
	int i, j, x;
	int n, sp;
	int k, m, w, size;
	uint64_t l;

	k = slices->K;
	m = slices->M;
	w = slices->W;
	size = slices->size;

	if (k > m) n = k;
	else n = m;
	sp = size * 2 + size/(w/8) + 8;

	printf("%-*sCoding\n", sp, "Data");
	for (i = 0; i < n; i++) {
		if (i < k) {
			printf("D%-2d:", i);
			for (j = 0; j < size; j+=(w/8)) {
				printf(" ");
				for (x = 0; x < w/8; x++){
					printf("%02x", (unsigned char)slices->ptrs[i][j+x]);
				}
			}
			printf("    ");
		}
		else printf("%*s", sp, "");
		if (i < m) {
			printf("C%-2d:", i);
			for (j = 0 ; j < size; j+=(w/8)) {
				printf(" ");
				for (x = 0; x < w/8; x++){
					printf("%02x", (unsigned char)slices->ptrs[i+k][j+x]);
				}
			}
		}
		printf("\n");
	}
	printf("\n");
}


int main(int argc, char **argv)
{
  uint64_t l;
	int sou;
  int k, w, i, j, m;
  JER_Matrix *jm;
  JER_Slices *slices;
  unsigned char *data;
  vector <int> erasures;
  vector <int> erased;
  
  if (argc != 3) usage((char *)NULL);
  if (sscanf(argv[1], "%d", &k) == 0 || k <= 0) usage((char *)"Bad k");
  if (sscanf(argv[2], "%d", &w) == 0 || (w != 8 && w != 16 && w != 32)) usage((char *)"Bad w");
  m = 2;
  if (w <= 16 && k + m > (1 << w)) usage((char *)"k + m is too big");

  jm = reed_sol_r6_coding_matrix(k, w);
	sou = sizeof(uint64_t);

  printf("Last 2 rows of the Distribution Matrix:\n\n");
  jm->Print();
  printf("\n");

  srand48(0);
  slices = new JER_Slices();
  slices->K = k;
  slices->M = 2;
  slices->W = w;
  slices->PS = sou;
  slices->size = slices->PS;

  slices->ptrs.resize(k+2);
	data = new unsigned char [sou * (k + 2)];
  for (i = 0; i < k; i++) {
    l = lrand48();
    l <<= 8*4;
    l += lrand48();
    memcpy(data+i*sou, &l, sou);
    slices->ptrs[i] = data + i*sou;
  }

  for (; i < k+2; i++) {
    slices->ptrs[i] = data + (i)*sou;
  }

  reed_sol_r6_encode(slices);


  printf("Encoding Complete:\n\n");
  print_data_and_coding(slices);

  erasures.resize(m);
  erased.resize(m+k);
  for (i = 0; i < m+k; i++) erased[i] = 0;
  l = 0;
  for (i = 0; i < m; ) {
    erasures[i] = lrand48()%(k+m);
    if (erased[erasures[i]] == 0) {
      erased[erasures[i]] = 1;
      memcpy(data + erasures[i]*sou, &l, sou);
      i++;
    }
  }

  printf("Erased %d random devices:\n\n", m);
  print_data_and_coding(slices);
  
  JER_Matrix_Decode(slices, jm, 0, erasures);

  printf("State of the system after decoding:\n\n");
  print_data_and_coding(slices);
  
  return 0;
}
